import { _decorator, Component, Node, tween, instantiate, Vec3, UIOpacity, UITransform } from 'cc';
const { ccclass, property } = _decorator;

/**
 * 弹窗基类
 */
@ccclass("PopupBase")
export class PopupBase<Options = any> extends Component {

    @property({ type: Node, tooltip: '背景遮罩' })
    public background: Node | null = null;
    @property({ type: Node, tooltip: '弹窗主体' })
    public main: Node | null = null;
    @property({ type: Node, tooltip: '拦截点击的节点' })
    public blocker: Node | null = null;
    /**
     * 展示/隐藏动画的时长
     */
    public animationDuration: number = 0.3;
    /**
     * 弹窗选项
     */
    protected options: Options | null = null;

    /**
     * 展示弹窗
     * @param options 弹窗选项
     * @param duration 动画时长
     */
    public async show(options?: Options, duration?: number) {
        // 储存选项
        this.options = options || null;
        // 初始化
        this.init(options);
        // 更新样式
        this.updateDisplay(options);
        // 弹窗回调
        this.onBeforeShow && await this.onBeforeShow();
        // 展示动画
        await this.playShowAnimation(duration || this.animationDuration);
        // 弹窗回调
        this.onAfterShow && this.onAfterShow();
    }

    /**
     * 隐藏弹窗
     * @param suspended 是否被挂起
     * @param duration 动画时长
     */
    public async hide(suspended: boolean = false, duration?: number) {
        const node = this.node;
        // 动画时长不为 0 时拦截点击事件（避免误操作）
        if (duration !== 0) {
            // if (!this.blocker) this.blocker = this.node.getChildByName('Blocker');
            this.blocker && (this.blocker.active = true);
        }
        // 弹窗回调
        this.onBeforeHide && await this.onBeforeHide(suspended);
        // 播放隐藏动画
        await this.playHideAnimation(duration || this.animationDuration);
        // 关闭拦截
        this.blocker && (this.blocker.active = false);
        // 关闭节点
        node.active = false;
        // 弹窗回调
        this.onAfterHide && this.onAfterHide(suspended);
        // 弹窗完成回调
        this.finishCallback && this.finishCallback(suspended);
    }

    /**
     * 播放弹窗展示动画（派生类请重写此函数以实现自定义逻辑）
     * @param duration 动画时长
     */
    protected playShowAnimation(duration: number): Promise<void> {
        return new Promise<void>(res => {
            // 初始化节点
            const background = this.background;
            // const main = this.main;
            this.node.active = true;

            if (background) {
                // 背景遮罩先设置为透明
                background.active = true;
                background.getComponent(UIOpacity)!.opacity = 0;
                // 背景遮罩显示
                tween(background.getComponent(UIOpacity))
                    .to(duration * 0.5, { opacity: 150 })
                    .start();
            }

            // 弹窗主体先设置为透明，大小缩放至0.5
            if (this.main) {
                this.main.active = true;
                this.main.scale = new Vec3(0.5, 0.5, 1);
                this.main.getComponent(UIOpacity)!.opacity = 0;
            }
            // 弹窗主体显示
            tween(this.main?.getComponent(UIOpacity))
                .to(duration, { opacity: 255 })
                .start();
            // 弹窗主体动画
            tween(this.main)
                .to(duration, { scale: new Vec3(1, 1, 1) }, { easing: 'backOut' })
                .call(res)
                .start();
        });
    }

    /**
     * 播放弹窗隐藏动画（派生类请重写此函数以实现自定义逻辑）
     * @param duration 动画时长
     */
    protected playHideAnimation(duration: number): Promise<void> {
        return new Promise<void>(res => {
            if (this.background) {
                // 背景遮罩
                tween(this.background.getComponent(UIOpacity))
                    .delay(duration * 0.5)
                    .to(duration * 0.5, { opacity: 0 })
                    .start();
            }

            // 弹窗主体
            tween(this.main?.getComponent(UIOpacity))
                .to(duration * 0.8, { opacity: 0 })
                .start();
            // 弹窗主体动画
            tween(this.main)
                .to(duration, { scale: new Vec3(0.1, 0.1, 1) }, { easing: 'backOut' })
                .call(res)
                .start();
        });
    }

    /**
     * 初始化（派生类请重写此函数以实现自定义逻辑）
     * @param options 弹窗选项
     */
    protected init(options?: Options) { 
    }

    /**
     * 更新样式（派生类请重写此函数以实现自定义逻辑）
     * @param options 弹窗选项
     */
    protected updateDisplay(options?: Options) { }

    /**
     * 弹窗展示前（派生类请重写此函数以实现自定义逻辑）
     */
    protected onBeforeShow(): Promise<void> {
        return new Promise(res => res());
    }

    /**
     * 弹窗展示后（派生类请重写此函数以实现自定义逻辑）
     */
    protected onAfterShow() { }

    /**
     * 弹窗隐藏前（派生类请重写此函数以实现自定义逻辑）
     * @param suspended 是否被挂起
     */
    protected onBeforeHide(suspended: boolean): Promise<void> {
        return new Promise(res => res());
    }

    /**
     * 弹窗隐藏后（派生类请重写此函数以实现自定义逻辑）
     * @param suspended 是否被挂起
     */
    protected onAfterHide(suspended: boolean) { }

    /**
     * 弹窗被挂起（派生类请重写此函数以实现自定义逻辑）
     */
    protected onSuspended(): Promise<void> {
        return new Promise(res => res());
    }

    /**
     * 弹窗流程结束回调（注意：该回调为 PopupManager 专用，重写 hide 函数时记得调用该回调）
     */
    protected finishCallback(suspended: boolean) {};

}